﻿using NBitcoin;
using NBitcoin.Altcoins.HashX11;
using Nethereum.Hex.HexConvertors.Extensions;
using Org.BouncyCastle.Crypto.Digests;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace JustMathCore.AddrToolCoin
{
    class TRON : AddrTools.IAddrConv
    {
        public AddrTools.AddrType Type
        {
            get
            {
                return AddrTools.AddrType.TRON;
            }
        }
        public string GetWif(byte[] prikey)
        {
            return prikey.ToHex();
        }
        public byte[] GetHashAddr(byte[] prikey)
        {
            //性能接近了
            if (curve == null)
                curve = Org.BouncyCastle.Crypto.EC.CustomNamedCurves.GetByName("secp256k1");
            var g = curve.G;
            var k = new Org.BouncyCastle.Math.BigInteger(1, prikey);
            var pubkey = g.Multiply(k).GetEncoded(false);
            if (pubkey.Length == 1)
                return null;


            var array = CalculateHash3K(pubkey, 1, 64);
            //array = CalculateHash3K(array, 0, array.Length);

            var hash = new byte[20];

            for (var i = 12; i < 32; i++)
            {
                hash[i - 12] = array[i];
            }

            return hash;
        }
        public string GetAddr(byte[] prikey)
        {
            var key = GetHashAddr(prikey);
            return Hash2Addr(key);
         
        }

        [ThreadStatic]
        static NBitcoin.DataEncoders.Base58CheckEncoder base58c;

        public byte[] Addr2Hash(string addr)
        {
            if(addr.IndexOf("41")==0)
            {
                return addr.Substring(2,40).HexToByteArray();
            }
            return AddrTools.base58Decode(addr).Skip(1).Take(20).ToArray();
        }

        public string Hash2Addr(byte[] hash)
        {
            byte[] newdata = new byte[21];
            if (hash.Length == 20)
            {

                newdata[0] = 0x41;

                Array.Copy(hash, 0, newdata, 1, 20);
            }
            else
            {
                Array.Copy(hash, newdata, 21);
            }

            var checksum = NBitcoin.Crypto.Hashes.SHA256(newdata, 0, 21);
            checksum = NBitcoin.Crypto.Hashes.SHA256(checksum);
            checksum = checksum.Take(4).ToArray();
            byte[] alldata = newdata.Concat(checksum).ToArray();
            string wif = AddrTools.base58Encode(alldata);
            return wif;
        }
        [ThreadStatic]
        static Org.BouncyCastle.Asn1.X9.X9ECParameters curve;

        [ThreadStatic]
        static Nethereum.Util.Sha3Keccack sha3k = null;
        [ThreadStatic]
        static KeccakDigest keccakDigest = null;
        [ThreadStatic]
        static byte[] hashout;
        public static byte[] CalculateHash3K(byte[] value, int begin, int count)
        {
            if (sha3k == null)
            {
                sha3k = new Nethereum.Util.Sha3Keccack();
                keccakDigest = new KeccakDigest(256);
                hashout = new byte[keccakDigest.GetDigestSize()];
            }
            keccakDigest.Reset();
            keccakDigest.BlockUpdate(value, begin, count);
            keccakDigest.DoFinal(hashout, 0);
            return hashout;
        }
    }

}
